﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Ecobee.Net
{
	/// <summary>
	/// The type of event. Values: hold, demandResponse, sensor, switchOccupancy, vacation, quickSave, today 
	/// </summary>
	public enum EventType
	{
		None,
		/// <summary>
		/// Hold temperature event.
		/// </summary>
		Hold,
		/// <summary>
		/// Demand Response event.
		/// </summary>
		DemandResponse,
		/// <summary>
		/// Sensor generated event.
		/// </summary>
		Sensor,
		/// <summary>
		/// EMS only event to flip unoccupied to occupied, and vice versa. Look at name to determine 
		/// whether "occupied" or "unoccupied".
		/// </summary>
		SwitchOccupancy,
		/// <summary>
		/// Vacation event.
		/// </summary>
		Vacation,
		/// <summary>
		/// Quick Save event.
		/// </summary>
		QuickSave,
		/// <summary>
		/// Today widget generated event.
		/// </summary>
		Today
	}

	/// <summary>
	/// The fan mode during the event. Values: auto, on Default: based on current climate and HVAC mode. 
	/// </summary>
	public enum FanSetMode
	{
		None,
		Auto,
		On
	}

	/// <summary>
	/// The event object represents a scheduled thermostat program change. All events have a start and 
	/// end time during which the thermostat runtime settings will be modified. Events may not be directly 
	/// modified, various Functions provide the capability to modify the calendar events and to modify the 
	/// program. The event list is sorted with events ordered by whether they are currently running and the 
	/// internal priority of each event. It is safe to take the first event which is running and show it as 
	/// the currently running event. When the resume function is used, events are removed in the order they 
	/// are listed here.
	/// </summary>
	public class Event : ApiObject
	{
		public EventType _type = EventType.None;
		private string _name = string.Empty;
		private bool _running = false;
		private DateTime _startDate = DateTime.MinValue;
		private Time _startTime = Time.Empty;
		private DateTime _endDate = DateTime.MinValue;
		private Time _endTime = Time.Empty;
		private bool _isOccupied = false;
		private bool _isCoolOff = false;
		private bool _isHeatOff = false;
		private double _coolHoldTemp = 0.0;
		private double _heatHoldTemp = 0.0;
		private FanSetMode _fan = FanSetMode.None;
		private VentilatorSetMode _vent = VentilatorSetMode.None;
		private int _ventilatorMinOnTime = 0;
		private bool _isOptional = false;
		private bool _isTemperatureRelative = false;
		private double _coolRelativeTemp = 0.0;
		private double _heatRelativeTemp = 0.0;
		private bool _isTemperatureAbsolute = false;
		private int _dutyCyclePercentage = 0;
		private int _fanMinOnTime = 0;
		private bool _occupiedSensorActive = false;
		private bool _unoccupiedSensorActive = false;
		private double _drRampUpTemp = 0.0;
		private double _drRampUpTime = 0.0;
		private string _linkRef = string.Empty;

		/// <summary>
		/// The type of event. Values: hold, demandResponse, sensor, switchOccupancy, vacation, quickSave, today 
		/// </summary>
		public EventType Type
		{
			get
			{
				return _type;
			}
			set
			{
				this.SetProperty(ref _type, value);
			}
		}

		/// <summary>
		/// The unique event name. 
		/// </summary>
		public string Name
		{
			get
			{
				return _name;
			}
			set
			{
				this.SetProperty(ref _name, value);
			}
		}

		/// <summary>
		/// Whether the event is currently active or not. 
		/// </summary>
		public bool Running
		{
			get
			{
				return _running;
			}
			set
			{
				this.SetProperty(ref _running, value);
			}
		}

		/// <summary>
		/// The event start date in thermostat local time.
		/// </summary>
		public DateTime StartDate
		{
			get
			{
				return _startDate;
			}
			set
			{
				this.SetProperty(ref _startDate, value);
			}
		}

		/// <summary>
		/// The event start time in thermostat local time.
		/// </summary>
		public Time StartTime
		{
			get
			{
				return _startTime;
			}
			set
			{
				this.SetProperty(ref _startTime, value);
			}
		}

		[JsonIgnore()]
		public DateTime StartDateTime
		{
			get
			{
				return this.StartDate.Add(this.StartTime);
			}
		}

		/// <summary>
		/// The event end date in thermostat local time.
		/// </summary>
		public DateTime EndDate
		{
			get
			{
				return _endDate;
			}
			set
			{
				this.SetProperty(ref _endDate, value);
			}
		}

		/// <summary>
		/// The event end time in thermostat local time.
		/// </summary>
		public Time EndTime
		{
			get
			{
				return _endTime;
			}
			set
			{
				this.SetProperty(ref _endTime, value);
			}
		}

		[JsonIgnore()]
		public DateTime EndDateTime
		{
			get
			{
				return this.EndDate.Add(this.EndTime);
			}
		}

		/// <summary>
		/// Whether there are persons occupying the property during the event. 
		/// </summary>
		public bool IsOccupied
		{
			get
			{
				return _isOccupied;
			}
			set
			{
				this.SetProperty(ref _isOccupied, value);
			}
		}

		/// <summary>
		/// Whether cooling will be turned off during the event. 
		/// </summary>
		public bool IsCoolOff
		{
			get
			{
				return _isCoolOff;
			}
			set
			{
				this.SetProperty(ref _isCoolOff, value);
			}
		}

		/// <summary>
		/// Whether heating will be turned off during the event. 
		/// </summary>
		public bool IsHeatOff
		{
			get
			{
				return _isHeatOff;
			}
			set
			{
				this.SetProperty(ref _isHeatOff, value);
			}
		}

		/// <summary>
		/// The cooling absolute temperature to set. 
		/// </summary>
		public double CoolHoldTemp
		{
			get
			{
				return _coolHoldTemp;
			}
			set
			{
				this.SetProperty(ref _coolHoldTemp, value);
			}
		}

		/// <summary>
		/// The heating absolute temperature to set.
		/// </summary>
		public double HeatHoldTemp
		{
			get
			{
				return _heatHoldTemp;
			}
			set
			{
				this.SetProperty(ref _heatHoldTemp, value);
			}
		}

		/// <summary>
		/// The fan mode during the event. Values: auto, on Default: based on current climate and HVAC mode.
		/// </summary>
		public FanSetMode Fan
		{
			get
			{
				return _fan;
			}
			set
			{
				this.SetProperty(ref _fan, value);
			}
		}

		/// <summary>
		/// The ventilator mode during the vent. Values: auto, minontime, on, off.
		/// </summary>
		public VentilatorSetMode Vent
		{
			get
			{
				return _vent;
			}
			set
			{
				this.SetProperty(ref _vent, value);
			}
		}

		/// <summary>
		/// The minimum amount of time the ventilator equipment must stay on on each duty cycle.
		/// </summary>
		public int VentilatorMinOnTime
		{
			get
			{
				return _ventilatorMinOnTime;
			}
			set
			{
				this.SetProperty(ref _ventilatorMinOnTime, value);
			}
		}

		/// <summary>
		/// Whether this event is mandatory or the end user can cancel it.
		/// </summary>
		public bool IsOptional
		{
			get
			{
				return _isOptional;
			}
			set
			{
				this.SetProperty(ref _isOptional, value);
			}
		}

		/// <summary>
		/// Whether the event is using a relative temperature setting to the currently active program climate.
		/// </summary>
		public bool IsTemperatureRelative
		{
			get
			{
				return _isTemperatureRelative;
			}
			set
			{
				this.SetProperty(ref _isTemperatureRelative, value);
			}
		}

		/// <summary>
		/// The relative cool temperature adjustment. 
		/// </summary>
		public double CoolRelativeTemp
		{
			get
			{
				return _coolRelativeTemp;
			}
			set
			{
				this.SetProperty(ref _coolRelativeTemp, value);
			}
		}

		/// <summary>
		/// The relative heat temperature adjustment. 
		/// </summary>
		public double HeatRelativeTemp
		{
			get
			{
				return _heatRelativeTemp;
			}
			set
			{
				this.SetProperty(ref _heatRelativeTemp, value);
			}
		}

		/// <summary>
		/// Whether the event uses absolute temperatures to set the values. Default: true for DRs.
		/// </summary>
		public bool IsTemperatureAbsolute
		{
			get
			{
				return _isTemperatureAbsolute;
			}
			set
			{
				this.SetProperty(ref _isTemperatureAbsolute, value);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public int DutyCyclePercentage
		{
			get
			{
				return _dutyCyclePercentage;
			}
			set
			{
				this.SetProperty(ref _dutyCyclePercentage, value);
			}
		}

		/// <summary>
		/// The minimum number of minutes to run the fan each hour. Range: 0-60, Default: 0
		/// </summary>
		public int FanMinOnTime
		{
			get
			{
				return _fanMinOnTime;
			}
			set
			{
				this.SetProperty(ref _fanMinOnTime, value);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool OccupiedSensorActive
		{
			get
			{
				return _occupiedSensorActive;
			}
			set
			{
				this.SetProperty(ref _occupiedSensorActive, value);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool UnoccupiedSensorActive
		{
			get
			{
				return _unoccupiedSensorActive;
			}
			set
			{
				this.SetProperty(ref _unoccupiedSensorActive, value);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public double DrRampUpTemp
		{
			get
			{
				return _drRampUpTemp;
			}
			set
			{
				this.SetProperty(ref _drRampUpTemp, value);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public double DrRampUpTime
		{
			get
			{
				return _drRampUpTime;
			}
			set
			{
				this.SetProperty(ref _drRampUpTime, value);
			}
		}

		/// <summary>
		/// Unique identifier set by the server to link one or more events and alerts together.
		/// </summary>
		public string LinkRef
		{
			get
			{
				return _linkRef;
			}
			set
			{
				this.SetProperty(ref _linkRef, value);
			}
		}

		protected override void OnFromDataObject(dynamic dataObject)
		{
			this.Type = dataObject.type;
			this.Name = dataObject.name;
			this.Running = dataObject.running;
			this.StartDate = dataObject.startDate;
			this.StartTime = ((JValue)dataObject.startTime).Value<string>();
			this.EndDate = dataObject.endDate;
			this.EndTime = ((JValue)dataObject.endTime).Value<string>();
			this.IsOccupied = dataObject.isOccupied;
			this.IsCoolOff = dataObject.isCoolOff;
			this.IsHeatOff = dataObject.isHeatOff;
			this.CoolHoldTemp = dataObject.coolHoldTemp / 10.0;
			this.HeatHoldTemp = dataObject.heatHoldTemp / 10.0;
			this.Fan = dataObject.fan;
			this.Vent = dataObject.vent;
			this.VentilatorMinOnTime = dataObject.ventilatorMinOnTime;
			this.IsOptional = dataObject.isOptional;
			this.IsTemperatureRelative = dataObject.isTemperatureRelative;
			this.CoolRelativeTemp = dataObject.coolRelativeTemp / 10.0;
			this.HeatRelativeTemp = dataObject.heatRelativeTemp / 10.0;
			this.IsTemperatureAbsolute = dataObject.isTemperatureAbsolute;
			this.DutyCyclePercentage = dataObject.dutyCyclePercentage;
			this.FanMinOnTime = dataObject.fanMinOnTime;
			this.OccupiedSensorActive = dataObject.occupiedSensorActive;
			this.UnoccupiedSensorActive = dataObject.unoccupiedSensorActive;
			this.DrRampUpTemp = dataObject.drRampUpTemp / 10.0;
			this.DrRampUpTime = dataObject.drRampUpTime / 10.0;
			this.LinkRef = dataObject.linkRef;
		}

		protected override string OnUniqueKey()
		{
			return this.Name;
		}

		protected override string OnGetKeyValue(dynamic dataObject)
		{
			return dataObject.name;
		}
	}
}
